﻿#pragma once

#include "MapObject.h"
#include "../../Shared/Enums.h"
#include "../MirGraphics/MLibrary.h"
#include "Frames.h"
#include "Effect.h"
#include "../../Shared/ServerPackets.h"
#include <string>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <any>
#include <optional>

using namespace Client::MirGraphics;
using namespace Client::MirNetwork;
using namespace Client::MirScenes;
using namespace Client::MirSounds;
using namespace Client::MirControls;
namespace S = ServerPackets;
namespace C = ClientPackets;
using namespace Client::MirScenes::Dialogs;

namespace Client::MirObjects
{
    class PlayerObject : public MapObject
    {
    public:
        virtual ~PlayerObject()
        {
            delete WeaponLibrary1;
            delete WeaponEffectLibrary1;
            delete WeaponLibrary2;
            delete HairLibrary;
            delete WingLibrary;
            delete MountLibrary;
            delete Frames;
            delete Frame;
            delete WingFrame;
            delete TargetPoint;
            delete ShieldEffect;
            delete ElementalBarrierEffect;
            delete ConcentratingEffect;
            delete FishingPoint;
        }

        ObjectType getRace() const override;

        bool getBlocking() const override;

        MirGender Gender = static_cast<MirGender>(0);
        MirClass Class = static_cast<MirClass>(0);
        unsigned char Hair = 0;
        unsigned short Level = 0;

        MLibrary *WeaponLibrary1, *WeaponEffectLibrary1, *WeaponLibrary2, *HairLibrary, *WingLibrary, *MountLibrary;
        int Armour = 0, Weapon = 0, WeaponEffect = 0, ArmourOffSet = 0, HairOffSet = 0, WeaponOffSet = 0, WingOffset = 0, MountOffset = 0;

        int DieSound = 0, FlinchSound = 0, AttackSound = 0;


        FrameSet *Frames;
        Frame *Frame, *WingFrame;
        int FrameIndex = 0, FrameInterval = 0, EffectFrameIndex = 0, EffectFrameInterval = 0, SlowFrameIndex = 0;
        unsigned char SkipFrameUpdate = 0;

        bool getHasClassWeapon() const;

        bool getHasFishingRod() const;

        Spell Spell = static_cast<Spell>(0);
        unsigned char SpellLevel = 0;
        bool Cast = false;
        unsigned int TargetID = 0;
        std::vector<unsigned int> SecondaryTargetIDs;
        Point *TargetPoint;

        bool MagicShield = false;
        Effect *ShieldEffect;

        bool ElementalBarrier = false;
        Effect *ElementalBarrierEffect;

        unsigned char WingEffect = 0;
    private:
        short StanceDelay = 2500;

        //ArcherSpells - Elemental system
    public:
        bool ElementalBuff = false;
        bool Concentrating = false;
        InterruptionEffect *ConcentratingEffect;
        bool ConcentrateInterrupted = false;
        bool HasElements = false;
        bool ElementCasted = false;
        int ElementEffect = 0; //hold orb count for player(object) load
        int ElementsLevel = 0;
        int ElementOrbMax = 0;
        //Elemental system END

        SpellEffect CurrentEffect = static_cast<SpellEffect>(0);

        bool RidingMount = false, Sprint = false, FastRun = false, Fishing = false, FoundFish = false;
        long long StanceTime = 0, MountTime = 0, FishingTime = 0;
        long long BlizzardStopTime = 0, ReincarnationStopTime = 0, SlashingBurstTime = 0;

        short MountType = -1, TransformType = -1;

        std::string GuildName;
        std::string GuildRankName;

        Point *FishingPoint;

        LevelEffects LevelEffects = static_cast<LevelEffects>(0);

        PlayerObject(unsigned int objectID);

        void Load(S::ObjectPlayer *info);
        void Update(S::PlayerUpdate *info);

        void ProcessBuffs();

        void MountUpdate(S::MountUpdate *info);

        void FishingUpdate(S::FishingUpdate *p);


        virtual void SetLibraries();

        virtual void SetEffects();

        void Process() override;
        virtual void SetAction();

        virtual void ProcessFrames();
        int UpdateFrame(bool skip = true);

        int UpdateFrame2();


        Missile *CreateProjectile(int baseIndex, MLibrary *library, bool blend, int count, int interval, int skip, int lightDistance = 6, bool direction16 = true, std::optional<Color*> &lightColour = std::nullopt, unsigned int targetID = 0) override;

        //Rebuild
        void PlayStepSound();
    private:
        void PlayWemadeStepSound(int x, int y, int &moveSound);

        void PlayShandaStepSound(int x, int y, int &moveSound);

        void PlayWemadeMir3StepSound(int x, int y, int &moveSound);


    public:
        void PlayStruckSound();
        void PlayFlinchSound();
        void PlayAttackSound();

        void PlayDieSound();

        void PlayMountSound();


        void Draw() override;

        void DrawBehindEffects(bool effectsEnabled) override;

        void DrawEffects(bool effectsEnabled) override;

        void DrawCurrentEffects();

        void DrawBlend() override;
        void DrawBody();
        void DrawHead();
        void DrawWeapon();
        void DrawWeapon2();
        void DrawWings();


        void DrawMount();

    private:
        bool IsVitalEffect(Effect *effect);

    public:
        void GetBackStepDistance(int magicLevel);

        void GetFlashDashDistance(int magicLevel);

        bool IsDashAttack();

        bool MouseOver(Point *p) override;

        void CreateLabel() override;

        void DrawName() override;

    };


    class QueuedAction
    {
    public:
        MirAction Action = static_cast<MirAction>(0);
        Point *Location;
        MirDirection Direction = static_cast<MirDirection>(0);
        std::vector<std::any> Params;
        virtual ~QueuedAction()
        {
            delete Location;
        }

    };

}
